package com.otitan.la.forest.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.otitan.la.forest.system.constant.StaticConstant;
import com.otitan.la.forest.system.dto.AreaDTO;
import com.otitan.la.forest.system.dto.CodeDTO;
import com.otitan.la.forest.system.entity.AreaEntity;
import com.otitan.la.forest.system.entity.AreaHistoryEntity;
import com.otitan.la.forest.system.mapper.AreaMapper;
import com.otitan.la.forest.system.service.AreaHistoryService;
import com.otitan.la.forest.system.service.AreaService;
import com.otitan.la.forest.system.util.DateTimeUtil;
import com.otitan.la.forest.system.vo.AreaEntityVO;
import com.otitan.la.forest.system.vo.AreaVO;
import com.otitan.webapp.framework.basepro.exception.code.BaseResponseCode;
import com.otitan.webapp.framework.basepro.model.DataResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AreaServiceImpl extends ServiceImpl<AreaMapper, AreaEntity> implements AreaService {


    @Value("${redis.key-prefix}")
    private String redisKeyPrefix;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private AreaHistoryService areaHistoryService;
    @Resource
    private AreaMapper areaMapper;

    @Transactional
    @Override
    public DataResult add(AreaEntity area, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return DataResult.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        if (isExist(area)) {
            return DataResult.fail("该地区名称或地区编码已存在！请重新输入");
        }
        boolean isSuccess = this.save(area);
        return addAreaHistory(area, isSuccess);
    }

    private boolean isExist(AreaEntity area) {
        //地区不能重复
        LambdaQueryWrapper<AreaEntity> queryWrapper = Wrappers.lambdaQuery();
        if (area.getId() != null) {
            queryWrapper.ne(AreaEntity::getId, area.getId());
        }
        queryWrapper.eq(AreaEntity::getAreaCode, area.getAreaCode());
        int count = this.count(queryWrapper);
        if (count > 0) {
            return true;
        }
        return false;
    }

    @Override
    public DataResult batchDelete(List<String> ids) {
        boolean isSuccess = this.removeByIds(ids);
        log.debug("\n>>>>>>>>> 【删除行政区划表】 <<<<<<<<<\n操作结果：{}，ids：{}\n>>>>>>>>> ---- <<<<<<<<<", isSuccess, ids);
        return DataResult.success();
    }

    @Transactional
    @Override
    public DataResult editor(AreaEntity area, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return DataResult.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        //地区不能重复
        if (isExist(area)) {
            return DataResult.fail("该地区名称或地区编码已存在！请重新输入");
        }
        //1.修改历史记录是上次行政区划数据（失效时间为当前时间）
        Page pagePlug = new Page(1, 1);
        LambdaQueryWrapper<AreaHistoryEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AreaHistoryEntity::getAreaId, area.getId());
        queryWrapper.orderByDesc(AreaHistoryEntity::getCreateDate);
        IPage<AreaHistoryEntity> iPage = areaHistoryService.page(pagePlug, queryWrapper);
        List<AreaHistoryEntity> areaHistories = iPage.getRecords();
        if (CollUtil.isNotEmpty(areaHistories)) {
            AreaHistoryEntity areaHistory = areaHistories.get(0);
            areaHistory.setUneffectDate(new Date());
            areaHistoryService.updateById(areaHistory);
        }
        boolean isSuccess = this.updateById(area);
        // 2.增加历史记录是当前提交的行政区划时间，生效时间从当前时间开始
        return addAreaHistory(area, isSuccess);
    }

    private DataResult addAreaHistory(AreaEntity area, boolean isSuccess) {
        AreaHistoryEntity areaHistoryEntity = new AreaHistoryEntity();
        BeanUtils.copyProperties(area, areaHistoryEntity);
        areaHistoryEntity.setId(null);
        areaHistoryEntity.setAreaId(area.getId());
        areaHistoryService.add(areaHistoryEntity);
        return isSuccess ? DataResult.success() : DataResult.fail(BaseResponseCode.DATA_NOT_EXIST.getMsg());
    }

    @Override
    public DataResult findPageData(long page, long size, AreaDTO area) {
        Page pagePlug = new Page(page, size);
        IPage<AreaEntityVO> iPage = pagePlug.setRecords(areaMapper.findPageData(area, pagePlug));
        return DataResult.success(iPage);
    }

    @Override
    public DataResult findOne(String id) {
        return DataResult.success(this.getById(id));
    }

    /**
     * 获取组织机构列表树
     *
     * @param
     * @return java.util.List<com.otitan.la.forest.system.vo.OrganizationTreeVO>
     * @throws
     * @author Sunke
     * @date 2020/9/21 0021 16:46
     */
    @Override
    public List<AreaVO> getAreaTree() {
        String date=DateTimeUtil.parseDate(new Date(),"yyyy-MM-dd HH:mm:ss");
        List<AreaVO> areaList = areaMapper.findAreaTree(date, null);
        List<AreaVO> areaTree = formatData(areaList, "0");
        return areaTree;
    }

    @Override
    public DataResult<List<AreaVO>> findAreaTreeByTwoLevels() {
        String date=DateTimeUtil.parseDate(new Date(),"yyyy-MM-dd HH:mm:ss");
        List<AreaVO> areaList = areaMapper.findAreaTree(date, "two");
        return DataResult.success(formatData(areaList, "0"));
    }

    public List<AreaVO> formatData(List<AreaVO> areaList, String parentCode) {
        if (CollectionUtil.isNotEmpty(areaList)) {
            List<AreaVO> otv = new ArrayList<>();
            areaList.forEach(item -> {
                if (parentCode.equals(item.getParentAreaCode())) {
                    otv.add(item);
                }
            });
            for (AreaVO areaVO : otv) {
                getMenuTree(areaVO, areaList);
            }
            return otv;
        }
        return null;
    }

    /**
     * 递归创建组织树
     *
     * @param area, orgList
     * @return void
     * @throws
     * @author Sunke
     * @date 2020/9/22 0022 11:40
     */
    private void getMenuTree(AreaVO area, List<AreaVO> orgList) {
        boolean flag = true;
        for (AreaVO areaVO : orgList) {
            if (area.getAreaCode().equals(areaVO.getParentAreaCode())) {
                getMenuTree(areaVO, orgList);
                area.getChildren().add(areaVO);
                area.setLeaf(Boolean.FALSE);
                flag = false;
            }
        }
        if (flag) {
            area.setLeaf(Boolean.TRUE);
        }
    }

    @Transactional
    @Override
    public DataResult makeAreaUneffect(String id) {
        AreaEntity area = this.getById(id);
        area.setUneffectDate(new Date());
        boolean isSuccess = this.updateById(area);
        Page pagePlug = new Page(1, 1);
        LambdaQueryWrapper<AreaHistoryEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AreaHistoryEntity::getAreaId, area.getId());
        queryWrapper.orderByDesc(AreaHistoryEntity::getCreateDate);
        IPage<AreaHistoryEntity> iPage = areaHistoryService.page(pagePlug, queryWrapper);
        List<AreaHistoryEntity> areaHistories = iPage.getRecords();
        if (CollUtil.isNotEmpty(areaHistories)) {
            AreaHistoryEntity areaHistory = areaHistories.get(0);
            areaHistory.setUneffectDate(new Date());
            isSuccess = areaHistoryService.updateById(areaHistory);
        }
        return isSuccess ? DataResult.success() : DataResult.fail(BaseResponseCode.DATA_NOT_EXIST.getMsg());
    }

    @Override
    public void saveToRedis() {
        List<AreaEntity> list = this.list();
        Map<String, String> collectMap = list.stream().collect(Collectors.toMap(AreaEntity::getAreaCode, AreaEntity::getAreaName));
        // 先删除Redis中的字典
        Set keys = redisTemplate.keys(redisKeyPrefix + StaticConstant.AREA);
        redisTemplate.delete(keys);
        redisTemplate.opsForHash().putAll(redisKeyPrefix + StaticConstant.AREA, collectMap);
    }


    /**
     * @return com.otitan.webapp.framework.basepro.model.DataResult
     * @throws [parentCode]
     * @Description:    通过父级编码查询子地区
     * @Author:        wangqingsong
     * @CreateDate:     2020/10/19 19:19
     */
    @Override
    public DataResult findCodeByParent(String parentCode) {
        List<String> codeList = new ArrayList<>();

        LambdaQueryWrapper<AreaEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AreaEntity::getParentAreaCode, parentCode);
        List<AreaEntity> areaList = this.list(queryWrapper);
        for (AreaEntity areaEntity : areaList) {
            codeList.add(areaEntity.getAreaCode());
        }

        codeList.add(parentCode);
        CodeDTO codeDTO = new CodeDTO();
        codeDTO.setCodeList(codeList);
        return DataResult.success(codeDTO);
    }
}